-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[libc][math] Implement nexttoward functions #72763
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-libc Author: Nishant Mittal (nishantwrp) ChangesImplements the cc: @lntue Patch is 27.50 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/72763.diff 23 Files Affected:
diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt
index 362138c92a6869f..da4a2345f389c49 100644
--- a/libc/config/darwin/arm/entrypoints.txt
+++ b/libc/config/darwin/arm/entrypoints.txt
@@ -199,6 +199,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
+ libc.src.math.nexttoward
+ libc.src.math.nexttowardf
+ libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
diff --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt
index 57d21a2ce273574..e29e75ec92dadcd 100644
--- a/libc/config/darwin/x86_64/entrypoints.txt
+++ b/libc/config/darwin/x86_64/entrypoints.txt
@@ -178,6 +178,9 @@ set(TARGET_LIBM_ENTRYPOINTS
#libc.src.math.nextafter
#libc.src.math.nextafterf
#libc.src.math.nextafterl
+ #libc.src.math.nexttoward
+ #libc.src.math.nexttowardf
+ #libc.src.math.nexttowardl
#libc.src.math.remainderf
#libc.src.math.remainder
#libc.src.math.remainderl
diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
index 5dda6aa71d36f81..ba86e31ee0adcd1 100644
--- a/libc/config/gpu/entrypoints.txt
+++ b/libc/config/gpu/entrypoints.txt
@@ -219,6 +219,8 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nearbyintf
libc.src.math.nextafter
libc.src.math.nextafterf
+ libc.src.math.nexttoward
+ libc.src.math.nexttowardf
libc.src.math.pow
libc.src.math.powf
libc.src.math.remainder
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 096e2afb06e5a9d..284feb7b99096ec 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -316,6 +316,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
+ libc.src.math.nexttoward
+ libc.src.math.nexttowardf
+ libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 7dadbc7f8285477..a5f0c91e32d0810 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -325,6 +325,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
+ libc.src.math.nexttoward
+ libc.src.math.nexttowardf
+ libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 83bc8461999ed66..63aa7473115a08e 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -329,6 +329,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
+ libc.src.math.nexttoward
+ libc.src.math.nexttowardf
+ libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 5611b399e8bca8b..4c0a6ec37fe4cc2 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -198,6 +198,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
+ libc.src.math.nexttoward
+ libc.src.math.nexttowardf
+ libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 4e38cb742d2844e..58c95b856535a12 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -492,6 +492,10 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"nextafter", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
FunctionSpec<"nextafterl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
+ FunctionSpec<"nexttowardf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<LongDoubleType>]>,
+ FunctionSpec<"nexttoward", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<LongDoubleType>]>,
+ FunctionSpec<"nexttowardl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
+
FunctionSpec<"powf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
FunctionSpec<"pow", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index 6d62a2d0fcdf2be..ff131195528ddb0 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -10,6 +10,7 @@
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_MANIPULATIONFUNCTIONS_H
#include "FPBits.h"
+#include "FloatProperties.h"
#include "NearestIntegerOperations.h"
#include "NormalFloat.h"
#include "PlatformDefs.h"
@@ -19,6 +20,7 @@
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+#include <fenv.h>
#include <limits.h>
#include <math.h>
@@ -169,8 +171,49 @@ LIBC_INLINE T nextafter(T from, T to) {
int_val = (to_bits.uintval() & sign_mask) + UIntType(1);
}
+ UIntType exponent_bits = int_val & FloatProperties<T>::EXPONENT_MASK;
+ if (exponent_bits == UIntType(0))
+ raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
+ else if (exponent_bits == FloatProperties<T>::EXPONENT_MASK)
+ raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
+
+ return cpp::bit_cast<T>(int_val);
+}
+
+template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
+LIBC_INLINE T nexttoward(T from, long double to) {
+ FPBits<T> from_bits(from);
+ if (from_bits.is_nan())
+ return from;
+
+ FPBits<long double> to_bits(to);
+ if (to_bits.is_nan())
+ return to;
+
+ if ((long double)from == to)
+ return to;
+
+ using UIntType = typename FPBits<T>::UIntType;
+ UIntType int_val = from_bits.uintval();
+ if (from != T(0.0)) {
+ if ((from < to) == (from > T(0.0))) {
+ ++int_val;
+ } else {
+ --int_val;
+ }
+ } else {
+ int_val = FPBits<T>::MIN_SUBNORMAL;
+ if (to_bits.get_sign())
+ int_val |= FloatProperties<T>::SIGN_MASK;
+ }
+
+ UIntType exponent_bits = int_val & FloatProperties<T>::EXPONENT_MASK;
+ if (exponent_bits == UIntType(0))
+ raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
+ else if (exponent_bits == FloatProperties<T>::EXPONENT_MASK)
+ raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
+
return cpp::bit_cast<T>(int_val);
- // TODO: Raise floating point exceptions as required by the standard.
}
} // namespace fputil
diff --git a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
index 52ef2568c1dce06..354739bab1b1998 100644
--- a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
+++ b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
@@ -59,6 +59,8 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
// which is what is expected. Since NaNs are handling separately,
// it will never overflow "beyond" infinity.
from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() + 1);
+ if (from_bits.is_inf())
+ raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
return from_bits;
} else {
++int_val;
@@ -105,6 +107,8 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
// which is what is expected. Since NaNs are handling separately,
// it will never overflow "beyond" infinity.
from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() + 1);
+ if (from_bits.is_inf())
+ raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
return from_bits;
} else {
++int_val;
@@ -112,8 +116,12 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
}
}
+ UIntType implicit_bit =
+ int_val & (UIntType(1) << MantissaWidth<long double>::VALUE);
+ if (implicit_bit == UIntType(0))
+ raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
+
return cpp::bit_cast<long double>(int_val);
- // TODO: Raise floating point exceptions as required by the standard.
}
} // namespace fputil
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 4aea54c7a457547..ffabc27bc00abc7 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -187,6 +187,10 @@ add_math_entrypoint_object(nextafter)
add_math_entrypoint_object(nextafterf)
add_math_entrypoint_object(nextafterl)
+add_math_entrypoint_object(nexttoward)
+add_math_entrypoint_object(nexttowardf)
+add_math_entrypoint_object(nexttowardl)
+
add_math_entrypoint_object(pow)
add_math_entrypoint_object(powf)
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 7ac365f55bb6f83..da59e74a8e822a8 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1474,6 +1474,42 @@ add_entrypoint_object(
-O2
)
+add_entrypoint_object(
+ nexttoward
+ SRCS
+ nexttoward.cpp
+ HDRS
+ ../nexttoward.h
+ DEPENDS
+ libc.src.__support.FPUtil.manipulation_functions
+ COMPILE_OPTIONS
+ -O2
+)
+
+add_entrypoint_object(
+ nexttowardf
+ SRCS
+ nexttowardf.cpp
+ HDRS
+ ../nexttowardf.h
+ DEPENDS
+ libc.src.__support.FPUtil.manipulation_functions
+ COMPILE_OPTIONS
+ -O2
+)
+
+add_entrypoint_object(
+ nexttowardl
+ SRCS
+ nexttowardl.cpp
+ HDRS
+ ../nexttowardl.h
+ DEPENDS
+ libc.src.__support.FPUtil.manipulation_functions
+ COMPILE_OPTIONS
+ -O2
+)
+
add_entrypoint_object(
fmod
SRCS
diff --git a/libc/src/math/generic/nexttoward.cpp b/libc/src/math/generic/nexttoward.cpp
new file mode 100644
index 000000000000000..38b45d6d2f65d9c
--- /dev/null
+++ b/libc/src/math/generic/nexttoward.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of nexttoward function -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/nexttoward.h"
+#include "src/__support/FPUtil/ManipulationFunctions.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(double, nexttoward, (double x, long double y)) {
+ return fputil::nexttoward(x, y);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/generic/nexttowardf.cpp b/libc/src/math/generic/nexttowardf.cpp
new file mode 100644
index 000000000000000..59a9f805a6946a1
--- /dev/null
+++ b/libc/src/math/generic/nexttowardf.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of nexttowardf function ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/nexttowardf.h"
+#include "src/__support/FPUtil/ManipulationFunctions.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float, nexttowardf, (float x, long double y)) {
+ return fputil::nexttoward(x, y);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/generic/nexttowardl.cpp b/libc/src/math/generic/nexttowardl.cpp
new file mode 100644
index 000000000000000..0c887ae0671bc98
--- /dev/null
+++ b/libc/src/math/generic/nexttowardl.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of nexttowardl function ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/nexttowardl.h"
+#include "src/__support/FPUtil/ManipulationFunctions.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(long double, nexttowardl, (long double x, long double y)) {
+ // We can reuse the nextafter implementation because nexttoward behaves
+ // exactly same as nextafter in case of long doubles. Also, we have explcitly
+ // handled the special 80-bit long doubles in nextafter implementation.
+ return fputil::nextafter(x, y);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/nexttoward.h b/libc/src/math/nexttoward.h
new file mode 100644
index 000000000000000..6a5bece9957689c
--- /dev/null
+++ b/libc/src/math/nexttoward.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for nexttoward --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_NEXTTOWARD_H
+#define LLVM_LIBC_SRC_MATH_NEXTTOWARD_H
+
+namespace LIBC_NAMESPACE {
+
+double nexttoward(double x, long double y);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_NEXTTOWARD_H
diff --git a/libc/src/math/nexttowardf.h b/libc/src/math/nexttowardf.h
new file mode 100644
index 000000000000000..7a0eb2a61b4d4b2
--- /dev/null
+++ b/libc/src/math/nexttowardf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for nexttowardf -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_NEXTTOWARDF_H
+#define LLVM_LIBC_SRC_MATH_NEXTTOWARDF_H
+
+namespace LIBC_NAMESPACE {
+
+float nexttowardf(float x, long double y);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_NEXTTOWARDF_H
diff --git a/libc/src/math/nexttowardl.h b/libc/src/math/nexttowardl.h
new file mode 100644
index 000000000000000..be1d8b298185d61
--- /dev/null
+++ b/libc/src/math/nexttowardl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for nexttowardl -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_NEXTTOWARDL_H
+#define LLVM_LIBC_SRC_MATH_NEXTTOWARDL_H
+
+namespace LIBC_NAMESPACE {
+
+long double nexttowardl(long double x, long double y);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_NEXTTOWARDL_H
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 101bdac995355de..298a1b1a400f1d8 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -1251,6 +1251,54 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
+# FIXME: These tests are currently spurious for NVPTX.
+if(NOT LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
+ add_fp_unittest(
+ nexttoward_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ nexttoward_test.cpp
+ HDRS
+ NextTowardTest.h
+ DEPENDS
+ libc.include.math
+ libc.src.math.nexttoward
+ libc.src.__support.FPUtil.basic_operations
+ libc.src.__support.FPUtil.fp_bits
+ )
+
+ add_fp_unittest(
+ nexttowardf_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ nexttowardf_test.cpp
+ HDRS
+ NextTowardTest.h
+ DEPENDS
+ libc.include.math
+ libc.src.math.nexttowardf
+ libc.src.__support.FPUtil.basic_operations
+ libc.src.__support.FPUtil.fp_bits
+ )
+endif()
+
+add_fp_unittest(
+ nexttowardl_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ nexttowardl_test.cpp
+ HDRS
+ NextTowardTest.h
+ DEPENDS
+ libc.include.math
+ libc.src.math.nexttowardl
+ libc.src.__support.FPUtil.basic_operations
+ libc.src.__support.FPUtil.fp_bits
+)
+
# TODO(lntue): The current implementation of fputil::general::fma<float> is only
# correctly rounded for the default rounding mode round-to-nearest tie-to-even.
add_fp_unittest(
diff --git a/libc/test/src/math/smoke/NextTowardTest.h b/libc/test/src/math/smoke/NextTowardTest.h
new file mode 100644
index 000000000000000..4d27592a11422bf
--- /dev/null
+++ b/libc/test/src/math/smoke/NextTowardTest.h
@@ -0,0 +1,223 @@
+//===-- Utility class to test different flavors of nexttoward ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TEST_SRC_MATH_NEXTTOWARDTEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_NEXTTOWARDTEST_H
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/type_traits.h"
+#include "src/__support/FPUtil/BasicOperations.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include <fenv.h>
+#include <math.h>
+
+#define ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, expected_exception) \
+ ASSERT_FP_EQ(result, expected); \
+ ASSERT_FP_EXCEPTION(expected_exception); \
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT)
+
+#define ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected) \
+ ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, FE_INEXACT | FE_UNDERFLOW)
+
+#define ASSERT_FP_EQ_WITH_OVERFLOW(result, expected) \
+ ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, FE_INEXACT | FE_OVERFLOW)
+
+template <typename T>
+class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::Test {
+ using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
+ using ToFPBits = LIBC_NAMESPACE::fputil::FPBits<long double>;
+ using MantissaWidth = LIBC_NAMESPACE::fputil::MantissaWidth<T>;
+ using UIntType = typename FPBits::UIntType;
+
+ static constexpr int BIT_WIDTH_OF_TYPE =
+ LIBC_NAMESPACE::fputil::FloatProperties<T>::BIT_WIDTH;
+
+ const T zero = T(FPBits::zero());
+ const T neg_zero = T(FPBits::neg_zero());
+ const T inf = T(FPBits::inf());
+ const T neg_inf = T(FPBits::neg_inf());
+ const T nan = T(FPBits::build_quiet_nan(1));
+
+ const long double to_zero = ToFPBits::zero();
+ const long double to_neg_zero = ToFPBits::neg_zero();
+ const long double to_nan = ToFPBits::build_quiet_nan(1);
+
+ const UIntType min_subnormal = FPBits::MIN_SUBNORMAL;
+ const UIntType max_subnormal = FPBits::MAX_SUBNORMAL;
+ const UIntType min_normal = FPBits::MIN_NORMAL;
+ const UIntType max_normal = FPBits::MAX_NORMAL;
+
+public:
+ typedef T (*NextTowardFunc)(T, long double);
+
+ void testNaN(NextTowardFunc func) {
+ ASSERT_FP_EQ(func(nan, 0), nan);
+ ASSERT_FP_EQ(func(0, to_nan), nan);
+ }
+
+ void testBoundaries(NextTowardFunc func) {
+ ASSERT_FP_EQ(func(zero, to_neg_zero), neg_zero);
+ ASSERT_FP_EQ(func(neg_zero, to_zero), zero);
+
+ // 'from' is zero|neg_zero.
+ T x = zero;
+ T result = func(x, 1);
+ UIntType expected_bits = 1;
+ T expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
+ ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
+
+ result = func(x, -1);
+ expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + 1;
+ expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
+ ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
+
+ x = n...
[truncated]
|
UIntType exponent_bits = int_val & FloatProperties<T>::EXPONENT_MASK; | ||
if (exponent_bits == UIntType(0)) | ||
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT); | ||
else if (exponent_bits == FloatProperties<T>::EXPONENT_MASK) | ||
raise_except_if_required(FE_OVERFLOW | FE_INEXACT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably test the exceptions in the tests for nextafter too. Will do that in a separate pr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM. Thanks for fixing this TODO item.
} | ||
|
||
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> | ||
LIBC_INLINE T nexttoward(T from, long double to) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For free function, I personally prefer to use SFINAE on the returning type LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> nexttoward(...)
, so that it frees the second template parameter to be used if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. just out of curiosity, what is the functional difference b/w the two approaches?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Essentially, when we do SFINAE with template<T, U = enable_if_t<..., void>>
, we do not intend to let user use the second template parameter, but nothing prevents user code to be func<T, U>(...)
, and it might silently get wrong function. If all users do is to call func(...)
or func<T>
then it doesn't matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding these functions! Overall LGTM with a few nits. Do you mind also updating the followings:
- bazel build: https://github.com/llvm/llvm-project/blob/main/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
- progress documentation: https://github.com/llvm/llvm-project/blob/main/libc/docs/math/index.rst
Thanks!
I've addressed the review comments, please review @lntue |
✅ With the latest revision this PR passed the C/C++ code formatter. |
0ada816
to
cde1efd
Compare
Follow up to #72763 (comment). ### Summary - Add unit tests for raising excepts in `nextafter`. - Fixed a bug in testing code for `nexttoward`. cc: @lntue
|
||
FPBits<long double> to_bits(to); | ||
if (to_bits.is_nan()) | ||
return to; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm observing the following warnings when building ninja check-libc
with clang:
[286/3491] Building CXX object projects/libc/src/math/gene...es/libc.src.math.generic.nexttowardf.dir/nexttowardf.cpp.o
In file included from /android0/llvm-project/libc/src/math/generic/nexttowardf.cpp:10:
/android0/llvm-project/libc/src/__support/FPUtil/ManipulationFunctions.h:191:12: warning: implicit conversion loses floating-point precision: 'long double' to 'cpp::enable_if_t<cpp::is_floating_point_v<float>, float>' (aka 'float') [-Wimplicit-float-conversion]
return to;
~~~~~~ ^~
/android0/llvm-project/libc/src/math/generic/nexttowardf.cpp:16:18: note: in instantiation of function template specialization '__llvm_libc_18_0_0_git::fputil::nexttoward<float>' requested here
return fputil::nexttoward(x, y);
^
In file included from /android0/llvm-project/libc/src/math/generic/nexttowardf.cpp:10:
/android0/llvm-project/libc/src/__support/FPUtil/ManipulationFunctions.h:194:12: warning: implicit conversion loses floating-point precision: 'long double' to 'cpp::enable_if_t<cpp::is_floating_point_v<float>, float>' (aka 'float') [-Wimplicit-float-conversion]
return to;
~~~~~~ ^~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That issue should be fixed by #73698. Are you on an updated checkout?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, thanks, slightly behind!
Implements the
nexttoward
,nexttowardf
andnexttowardl
functions. Also, raise excepts required by the standard innextafter
functions.cc: @lntue